#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>


using namespace std;
using namespace cv;

#include <vector>

bool  is_rect_in_range(Rect rect, Rect Range)
{
   if(  rect.x >= Range.x && rect.y >= Range.y 
      &&rect.x+rect.width  <= Range.x + Range.width
      &&rect.y+rect.height <= Range.y + Range.height
     ) 
       return true;

   return false;
}

bool  is_rect_intersect(Rect rect, Rect Range)
{
   Rect inter = rect & Range;	
   if(  inter.width > 0 && inter.height > 0 ) 
       return true;

   return false;
}

bool is_elem_in_array(vector<Rect> container, Rect elem)
{
   for(int i = 0; i < container.size(); i++){
       Rect rect = container[i];
       if(    rect.x     == elem.x     && rect.y      == elem.y 
           && rect.width == elem.width && rect.height == elem.height
	 )
	 return true;      
   }

   return false;
}

int main(int argc, char** argv)
{
   Mat img;

   int line_no = 0;
   if(argc >= 2)	
       img = imread(argv[1]);
   else{
       cout << "Usage: ./cv_contours file" << endl;
       return -1;
   }

   if(argc == 3)
       line_no = atoi(argv[2]);


   Mat imgCopy(img);
   Mat imgCopy2(img.clone());
   Mat imgCopy3(img.clone());
   //Mat imgCopy2(img);

   Mat imgGray;

   cvtColor(img, imgGray, COLOR_BGR2GRAY);

   //imshow("Gray", imgGray);
   
   Mat blurMat;

   blur(imgGray, blurMat, Size(3,3));

   //imshow("blur", blurMat);


   Mat dstImage;


//   Canny(blurMat, dstImage, 100, 200);
   //Canny(blurMat, dstImage, 50, 200);

//   imshow("canny", dstImage);
  
   threshold(blurMat, dstImage, 192, 255, THRESH_BINARY) ;

   //imshow("thresh", dstImage);

   vector<vector<Point>> contours;

   Mat edges(dstImage);

   //findContours(edges, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
   //findContours(edges, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
   //findContours(edges, contours, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
   findContours(edges, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
//   findContours(edges, contours, RETR_TREE, CHAIN_APPROX_TC89_L1);
//   findContours(edges, contours, RETR_TREE, CHAIN_APPROX_TC89_KCOS);

   std::cout << "There are " << contours.size() << " contours" << endl;

   Mat resizeImage;

   int obj_total = 0;

   vector<Rect> RectArray, simpleRectArray, intersectRectArray, unionRectArray;

   for(int i = 0; i < contours.size(); i++){
       Rect  rect = boundingRect(contours[i]);
       //if(rect.area() >= 25 && rect.width >=5    && rect.height >=5 
       //		            && rect.width <= 200 && rect.height <= 200 ){
       if(1){
          if(line_no){
	      if(rect.y >= line_no*200 && rect.y <= (line_no*200+400))
		   ;
	      else 
		  continue;
	  }

	  if(rect.x <= 300 || (rect.x >= 2900 && rect.x <= 3550) || rect.x >= 5700)
	      continue;

	  if(rect.area() < 16)
              continue;
          if(rect.height <= 6)	  
	      continue;
          if(rect.width  > 400)	  
	      continue;

	  obj_total++;

          rectangle(imgCopy, rect, Scalar(0, 0, 255));
         // imshow("edges", imgCopy);
	 

	  if(! is_elem_in_array(RectArray, rect))
       	      RectArray.push_back(rect);
  
	 // if(i % 100 == 0){
	  //destroyAllWindows();
          //resize(imgCopy, resizeImage, Size(), 0.2, 0.2);
          //imshow("resize1", resizeImage);

	  cout << "rect.width and height are: " << rect.width << " " << rect.height << endl;
#define ROI_RANGE  20
	  int xl = MAX(0, rect.x - ROI_RANGE);
	  int xr = MIN(imgCopy.cols, rect.x + rect.width  + ROI_RANGE);
	  int yt = MAX(0, rect.y - ROI_RANGE);
	  int yb = MIN(imgCopy.rows, rect.y + rect.height + ROI_RANGE);
          Rect outter(xl, yt, xr-xl, yb-yt);

          Rect inner(rect.x+1, rect.y+1, rect.width-2, rect.height-2);
//	  rectangle(imgCopy, inner , Scalar(0, 255, 0));
//	  rectangle(imgCopy, outter, Scalar(0, 0, 255));


          //Rect roi(rect.x, rect.y, rect.width, rect.height);
          Rect roi(outter.x, outter.y, outter.width, outter.height);
          //Rect roi(rect.x-2, rect.y-2, rect.width+4, rect.height+4);

          //Mat roiImage =  imgCopy(roi);
          Mat roiImage =  imgCopy(outter);
	  cout << "roiImage.width and height are: " << roiImage.cols << " " << roiImage.rows << endl;

	  destroyAllWindows();
          namedWindow("roi", WINDOW_NORMAL);
	  imshow("roi", roiImage);

	  //if(i % 100 == 0) 
	  //    waitKey(0);
	  //else
          //    waitKey(1000);
	  cout << i << " second" << endl;
	  //}
	  
	  
       }
   }
      

   cout << "Total "<< obj_total << " objects counted\n" << endl;
   cout << "or Total "<< RectArray.size() << " elements counted\n" << endl;



   for(int j = 0; j < RectArray.size(); j++){
       bool is_inside = false;	   
       for(int i = 0; i < RectArray.size(); i++){	   
           if(i == j)
	        continue;
           if( is_rect_in_range(RectArray[j], RectArray[i]) ){
	        is_inside = true;
		break;
	   }
	   
       }
       if(!is_inside){
	       
	  if(! is_elem_in_array(simpleRectArray, RectArray[j]))
    	      simpleRectArray.push_back(RectArray[j]);
       }
   }
       
   //for(int i = 0; i < simpleRectArray.size(); i++){	   
   //    rectangle(imgCopy2, simpleRectArray[i], Scalar(255, 0, 0));
   //}

   cout << "simple Total "<< simpleRectArray.size() << " elements counted\n" << endl;








   for(int j = 0; j < simpleRectArray.size(); j++){
       bool is_intersect = false;	   
       for(int i = 0; i < simpleRectArray.size(); i++){	   
           if(i == j)
	        continue;
           if( is_rect_intersect(simpleRectArray[j], simpleRectArray[i]) ){
	       // is_intersect = true;
                Rect tmp_rect = simpleRectArray[j] | simpleRectArray[i]; 
	        if(! is_elem_in_array(intersectRectArray, tmp_rect))
    	             intersectRectArray.push_back( tmp_rect);
		//break;
	   }
	   
       }
   }
       
   //for(int i = 0; i < intersectRectArray.size(); i++){	   
       //rectangle(imgCopy2, intersectRectArray[i], Scalar(0, 255, 0));
   //}

   cout << "intersect Total "<< intersectRectArray.size() << " elements counted\n" << endl;


   for(int i = 0; i < intersectRectArray.size(); i++){	   
       if( ! is_elem_in_array(simpleRectArray, intersectRectArray[i]) )	   
           simpleRectArray.push_back(intersectRectArray[i]);    
   }
   cout << "simple + intersect Total "<< simpleRectArray.size() << " elements counted\n" << endl;
   for(int i = 0; i < simpleRectArray.size(); i++){	   
       rectangle(imgCopy2, simpleRectArray[i], Scalar(255, 0, 0));
   }









   for(int i = 0; i < simpleRectArray.size(); i++){


#define EXTERNAL_RANGE   30       
       Rect rectSearchRange(
		            simpleRectArray[i].x - EXTERNAL_RANGE,
		            simpleRectArray[i].y - EXTERNAL_RANGE,
		            simpleRectArray[i].width  + 2*EXTERNAL_RANGE,
		            simpleRectArray[i].height + 2*EXTERNAL_RANGE
		           );


       for(int j = 0; j < simpleRectArray.size(); j++){
       //for(int j = 0; j < simpleRectArray.size()-i; j++){
           if(j == i)
	        continue;

           if( is_rect_intersect(simpleRectArray[j], rectSearchRange) ){
               Rect union_rect = simpleRectArray[j] | simpleRectArray[i];
	       if(  union_rect.width <= 200 && union_rect.height <= 200
   //		 && union_rect.width >= 30  && union_rect.height >= 30
		 ){
                    if( ! is_elem_in_array(unionRectArray, union_rect) ){	   
		        unionRectArray.push_back(union_rect);
                        rectangle(imgCopy2, union_rect, Scalar(0, 0, 255));
		    }
	       }
               /* 
               Rect roi(xl,yt, xr-xl, yb-yt);

               Mat roiImage =  imgCopy(roi);

               imshow("roi", roiImage);

	       waitKey(0);
	       */

	   }     
       }
   }
   cout << "union Total "<< unionRectArray.size() << " elements counted\n" << endl;





   //save as file
   for(int i = 0; i < simpleRectArray.size(); i++){	   
        Mat roi = imgCopy3(simpleRectArray[i]);
	char name[16] = {0};
	sprintf(name, "s%04d.jpg", i+1);
        bool isSaved = imwrite(name, roi);	
	if(isSaved)
		;//cout <<"(simple) " << i+1 <<" OK" << endl;
	else{
		cout <<"(simple) " << i+1 << " fail, please check." << endl;
		break;
	}
   }
   for(int i = 0; i < unionRectArray.size(); i++){	   
        Mat roi = imgCopy3(unionRectArray[i]);
	char name[16] = {0};
	sprintf(name, "u%04d.jpg", i+1);
        bool isSaved = imwrite(name, roi);	
	if(isSaved)
		;//cout << i+1 <<" OK" << endl;
	else{
		cout << "(union) "<< i+1 << " fail" << endl;
		break;
	}
   }




   
   //resize(imgCopy, resizeImage, Size(), 0.2, 0.2);
   //imshow("resize", resizeImage);

//   Rect roi_line(0, line_no*200, imgCopy.cols,400);
//   Mat  roi_lineImage = imgCopy(roi_line);
   Rect roi_line(0, line_no*200, imgCopy2.cols,  line_no == 0? imgCopy2.rows:400);
   Mat  roi_lineImage = imgCopy2(roi_line);
   destroyAllWindows();
   imshow("roi_line", roi_lineImage);



   waitKey(0);
   return 0;

/*
   int x = 200,y = 200, width = img.size().width-2*x, height = img.size().height-2*y;
   cv::Rect roi(x,y, width, height);

   cv::Mat roiImage =  img(roi);
   bool isSaved = cv::imwrite("output.jpg", roiImage);
   if(isSaved)
	   std::cout << "OK"   << std::endl;
   else
	   std::cout << "fail" << std::endl;


   imshow("LOVE", img);

   waitKey(0);
   return 0;
*/   
}

